有node
<template>
    <div class="tree-container">
        <!-- 渲染树形结构 -->
        <ul>
    <li v-for="child in filteredChildren(item)" :key="child.oid">
        <span :style="getIndentationStyle(0)">
            <span @click.stop="toggle(child)" :class="{
                'caret-down': isExpanded[child.oid],
                'caret-right': !isExpanded[child.oid]
            }" class="caret-icon"></span>
            <SvgIcon iconClass="team" class="team-icon" />
            <span @click="selectNode(child)" :class="{ selected: selectedNodeOid === child.oid }">
                {{ decodeURIComponent(child.oname) }}
            </span>
        </span>
        <ul v-if="child.children && isExpanded[child.oid]">
            <!-- 递归渲染子节点 -->
            <li v-for="subChild in filteredChildren(child.children)" :key="subChild.oid">
                <span :style="getIndentationStyle(1)">
                    <span @click.stop="toggle(subChild)" :class="{
                        'caret-down': isExpanded[subChild.oid],
                        'caret-right': !isExpanded[subChild.oid]
                    }" class="caret-icon"></span>
                    <SvgIcon iconClass="team" class="team-icon" />
                    <span @click="selectNode(subChild)" :class="{ selected: selectedNodeOid === subChild.oid }">
                        {{ decodeURIComponent(subChild.oname) }}
                    </span>
                </span>
                <ul v-if="subChild.children && isExpanded[subChild.oid]">
                    <!-- 继续递归渲染 -->
                    <li v-for="subSubChild in filteredChildren(subChild.children)" :key="subSubChild.oid">
                        <span :style="getIndentationStyle(2)">
                            <SvgIcon iconClass="team" class="team-icon" />
                            <span @click="selectNode(subSubChild)" :class="{ selected: selectedNodeOid === subSubChild.oid }">
                                {{ decodeURIComponent(subSubChild.oname) }}
                            </span>
                        </span>
                    </li>
                </ul>
            </li>
        </ul>
    </li>
</ul>
    </div>
</template>

<script>
import SvgIcon from '@/components/SvgIcon';

export default {
    components: {
        SvgIcon,
    },
    name: 'TreeItem',
    props: {
        item: Object,
        searchQuery: String, // 从父组件传递的搜索查询
        selectedNodeOid: String,
        parent: Object, // 父节点传递
    },
    data() {
        return {
            isExpanded: {},
        };
    },
    created() {
        this.item.children.forEach(child => {
            this.$set(this.isExpanded, child.oid, false);
        });
    },
    methods: {
        toggle(node) {
            // 切换展开/折叠状态
            this.$set(this.isExpanded, node.oid, !this.isExpanded[node.oid]);
        },

        selectNode(node) {
            const parentSid = node.parent ? node.parent.oid : null;
            this.$emit('node-selected', { title: node.oname, oid: node.oid, selectedSid: parentSid });
            if (this.selectedNodeOid !== node.oid) {
                this.selectedNodeOid = node.oid;
            }
        },

        filteredChildren(children) {
        if (!this.searchQuery) {
            return children; // 如果没有搜索框输入，返回所有子节点
        }

        return children.filter(child => {
            const decodedName = decodeURIComponent(child.oname); // 解码名称
            if (decodedName.includes(this.searchQuery)) {
                return true;
            }

            // 如果当前节点有子节点，递归过滤
            if (child.children && child.children.length > 0) {
                const filteredSubChildren = this.filteredChildren(child.children); // 递归地过滤子节点
                return filteredSubChildren.length > 0;
            }

            return false;
        });
    },

        // 根据节点的层级动态计算缩进
        getIndentationStyle(level) {
            return { paddingLeft: `${level * 5}px`, display: 'inline-flex', alignItems: 'center' };
        },
    },
};
</script>
  
   
<style scoped>
.tree-container {
    margin: 10px;
}

.tree-search {
    margin-bottom: 10px;
}

.el-input {
    width: 240px;
}

ul {
    list-style-type: none;
    padding-left: 10px;
}

li {
    cursor: pointer;
}

span {
    font-weight: bold;
    color: #6c757d;
    display: inline-flex;
    align-items: center;
}

.selected {
    color: #007bff;
    /* 选中节点的文本颜色 */
}

.caret-down::before,
.caret-right::before {
    content: '';
    display: inline-block;
    width: 0;
    height: 0;
    border-style: solid;
    color: #6c757d;
}

.caret-down::before {
    border-width: 7px 7px 0 7px;
    border-color: #6c757d transparent transparent transparent;
}

.caret-right::before {
    border-width: 7px 0 7px 7px;
    border-color: transparent transparent transparent #6c757d;
}

.caret-down,
.caret-right {
    user-select: none;
    margin-right: 2px;
}

.team-icon {
    margin-right: 5px;
}

.caret-icon {
    cursor: pointer;
    user-select: none;
    margin-right: 2px;
}
</style>
